/*
Chris Elrod
10/27/2008
CSci 252
Prof. Hasan

Project 2 - EJB

Reference: 
    BEA trader example: BEA 10.3 HOME\wlserver_10.3\samples\server\examples\src\examples\ejb\ejb20\basic\statefulSession
*/

package examples.ejb.ejb20.basic.Project2;


import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.ejb.RemoveException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import weblogic.ejbgen.*;
import java.io.File;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.util.Scanner;
import java.util.regex.Pattern;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Vector;



/**
 * TransactionBean is a stateless Session Bean. This bean illustrates:
 * <ul>
 * <li> No persistence of state between calls to the Session Bean
 * <li> Looking up values from the Environment
 * </ul>
 *
 */


@FileGeneration(remoteClass = Constants.Bool.TRUE,
                localHome = Constants.Bool.FALSE,
                remoteHome = Constants.Bool.TRUE,
                remoteClassName = "Transaction",
                remoteHomeName = "TransactionHome",
                localClass = Constants.Bool.FALSE)
@JarSettings(ejbClientJar = "Project2_client.jar")
@JndiName(remote = "Project2-Transaction-TransactionHome")
@Session(idleTimeoutSeconds = "600",
         maxBeansInCache = "1000",
         transTimeoutSeconds = "0",
         type = Session.SessionType.STATEFUL,
         defaultTransaction = Constants.TransactionAttribute.REQUIRED,
         ejbName = "statelessSession_Transaction",
         enableCallByReference = Constants.Bool.TRUE)


public class TransactionBean implements SessionBean {


  private SessionContext ctx;
  private String file_path = "C:/bea/wlserver_10.3";
  private Hashtable table_transaction = new Hashtable();


  private String url = "t3://localhost:7001";
  private static final String JNDI_NAME = "Project2-Inventory-InventoryHome";
  private InventoryHome home;


  public TransactionBean() throws NamingException {
  
    home = lookupHome();  
  }


  private void log(String s) {
    System.out.println(s);
  } 

  
  /**
   * This method is required by the EJB Specification,
   * but is not used by this example.
   */
  public void ejbActivate() {
    log("ejbActivate called");
  }


  /**
   * This method is required by the EJB Specification,
   * but is not used by this example.
   */
  public void ejbRemove() {
    log("ejbRemove called");
  }


  /**
   * This method is required by the EJB Specification,
   * but is not used by this example.
   */
  public void ejbPassivate() {
    log("ejbPassivate called");
  }


  /**
   * 
   * This method is required by the EJB Specification,
   * but is not used by this example.
   *
   * Sets the session context.
   *
   * @param ctx               SessionContext Context for session
   */
  public void setSessionContext(SessionContext ctx) {
    log("setSessionContext called");
    this.ctx = ctx;
  }


  /**
   * 
   *
   * This method corresponds to the create method in the home interface
   * "TransactionHome.java".
   * The parameter sets of the two methods are identical. When the client calls
   * <code>TransactionHome.create()</code>, the container allocates an instance of 
   * the EJBean and calls <code>ejbCreate()</code>.
   *
   * @exception               javax.ejb.CreateException if there is
   *                          a communications or systems failure
   * @see                     examples.ejb.ejb20.basic.statelessSession.Transaction
   */

  public void ejbCreate () throws CreateException {
    log("ejbCreate called");

    try {
      InitialContext ic = new InitialContext();
    } catch (NamingException ne) {
      throw new CreateException("Failed to find environment value "+ne);
    }
  }


  /*Adds a request. Parms a string, request info.  Returns a boolean, based on success.*/ 
  @RemoteMethod()

  public boolean addRequest (String requestinfo){
    
    log("1: " + table_transaction.toString()); 
    int key = table_transaction.size() + 1;
    
    log("2: " + table_transaction.toString());
    try{
      table_transaction.put( key, new String(requestinfo) );
    }catch(NullPointerException ae){ 
      log("An Exception has been thrown in TransactionBean's addRequest method: " + ae);  
      return false;
    }
    
    log("3: " + table_transaction.toString());

    log("4: " + table_transaction.toString());
    return true;
  } 


  /*Whenever a request is approved the inventory is updated and the request is removed from the hashtable 'table_transaction'
    and logged into a new file called approved_requests.txt.
    Utility for internal bean, models an internal control system.  Approval work.
    Parms: id.  Returns a boolean based on success*/
  @RemoteMethod()

  public boolean approveTransaction(String id) throws CreateException, RemoteException, RemoveException{

    //Update the inventory.
    Integer position = new Integer(id);
    Inventory inventory = (Inventory) narrow(home.create(), Inventory.class);
    inventory.add( getISBN( getTitle(position) ) , getTitle(position) , getQuantity(position) );

    //Log the request.
    File input_file = new File(file_path, "approved_requests.txt");
    try{
      BufferedWriter out = new BufferedWriter( new FileWriter(input_file, true) );    
      out.write( table_transaction.get(position).toString() ) ;
      out.newLine(); 
      out.close();
    }catch(Exception ae){ 
      log("Exception in TransactionBean's approveTransaction(String id) " + ae);
      return false;
    }   

    //Remove from hastable.
    table_transaction.remove(position);

    return true;
  } 
  

  /*Whenever a request is rejected it is also removed from the hashtable 'table_transaction' and put into 
    a new file called rejected_requests.txt.  Utility for internal bean, models an internal control system.  
    Rejection work.
    Parms string id.  Returns a boolean based on the success.*/
  @RemoteMethod()

  public boolean rejectTransaction(String id) throws CreateException, RemoteException, RemoveException{

    //Update the inventory.
    Integer position = new Integer(id);
    Inventory inventory = (Inventory) narrow(home.create(), Inventory.class);
    inventory.remove( getISBN( getTitle(position) ) , getTitle(position) , getQuantity(position) );

    //Log the request.
    File input_file = new File(file_path, "rejected_requests.txt");
    try{
      BufferedWriter out = new BufferedWriter( new FileWriter(input_file, true) );    
      out.write( table_transaction.get(position).toString() ) ;
      out.newLine(); 
      out.close();
    }catch(Exception ae){ 
      log("Exception in TransactionBean's rejectTransaction(String id) " + ae);
      return false;
    }   

    //Remove from hastable.
    table_transaction.remove(position);

    return true;
  } 


  /*Gets a request's title.*/ 
  @RemoteMethod()

  public Vector getIds(){
     return new Vector(table_transaction.keySet());
  }


  /*Gets a request's title.*/ 
  @RemoteMethod()

  public String getTitle (int position){

    Scanner sc = new Scanner( table_transaction.get(position).toString() );
    sc.useDelimiter( Pattern.compile("\\*") );

    return new String(sc.next().trim());  
  }


  /*Gets a request's ISBN.*/ 
  @RemoteMethod()

  public String getISBN (String title){
       
    Integer temp;

    for (Enumeration e = table_transaction.keys() ; e.hasMoreElements() ;) {

      temp = new Integer( e.nextElement().toString() );

      if ( getTitle(temp).equals(title) ){
        Scanner sc = new Scanner( table_transaction.get(temp).toString() );
        sc.useDelimiter( Pattern.compile("\\*") );
        sc.next();
        return new String(sc.next().trim());
      }
    }

      return null;  

  }
 

  /*Gets a request's quantity.*/ 
  @RemoteMethod()

  public int getQuantity (int position){

    Scanner sc = new Scanner( table_transaction.get(position).toString() );
    sc.useDelimiter( Pattern.compile("\\*") );
    sc.next();
    sc.next();

    return new Integer(sc.next().trim());  
  } 


  /*Gets a request's name.*/ 
  @RemoteMethod()

  public String getName (int position){

    Scanner sc = new Scanner( table_transaction.get(position).toString() );
    sc.useDelimiter( Pattern.compile("\\*") );
    sc.next();
    sc.next();
    sc.next();

    return new String(sc.next().trim());
  } 


  /*Gets a request's address.*/ 
  @RemoteMethod()

  public String getAddress (int position){

    Scanner sc = new Scanner( table_transaction.get(position).toString() );
    sc.useDelimiter( Pattern.compile("\\*") );
    sc.next();
    sc.next();
    sc.next();
    sc.next();

    return new String(sc.next().trim());  
  } 


  /*Gets a request's organization.*/ 
  @RemoteMethod()

  public String getOrganization (int position){

    Scanner sc = new Scanner( table_transaction.get(position).toString() );
    sc.useDelimiter( Pattern.compile("\\*") );
    sc.next();
    sc.next();
    sc.next();
    sc.next();
    sc.next();

    return new String(sc.next().trim());  
  }

  /**
   * RMI/IIOP clients should use this narrow function
   */
  private Object narrow(Object ref, Class c) {
    return PortableRemoteObject.narrow(ref, c);
  }


  /**
   * Lookup the EJBs home in the JNDI tree
   */
  private InventoryHome lookupHome() throws NamingException {
    // Lookup the beans home using JNDI
    Context ctx = getInitialContext();

    try {
      Object home = ctx.lookup(JNDI_NAME);
      return (InventoryHome) narrow(home, InventoryHome.class);
    } catch (NamingException ne) {
      log("The client was unable to lookup the EJBHome.  Please make sure ");
      log("that you have deployed the ejb with the JNDI name "+
        JNDI_NAME+" on the WebLogic server at "+url);
      throw ne;
    }
  }


  /**
   * Using a Properties object will work on JDK 1.1.x and Java2
   * clients
   */
  private Context getInitialContext() throws NamingException {
    
    try {
      // Get an InitialContext
      Hashtable<String,String> h = new Hashtable<String,String>();
      h.put(Context.INITIAL_CONTEXT_FACTORY,
        "weblogic.jndi.WLInitialContextFactory");
      h.put(Context.PROVIDER_URL, url);
      return new InitialContext(h);
    } catch (NamingException ne) {
      log("We were unable to get a connection to the WebLogic server at "+url);
      log("Please make sure that the server is running.");
      throw ne;
    }
  }




}








